package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 公共字段填充的实现
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    //切入点
    @Pointcut("@annotation(com.sky.annotation.AutoFill)&& execution(* com.sky.mapper.*.*(..))")
    private void pt() {}

    //切面，前置通知
    @Before("pt()")
    public void autoFill(JoinPoint joinPoint) {
        log.info(" 公共字段填充的实现,参数为：{}", joinPoint);
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取getSignature的子类，专门对方法操作
        //1.取得目标方法上的自定义注解
        AutoFill autoFillAnn = signature.getMethod().getAnnotation(AutoFill.class);
        //获取注解上的值：INSERT/UPDATE
        OperationType type = autoFillAnn.value();
        //2.获取方法的参数的数组,约定好实体对象放第一个参数
        Object[] args = joinPoint.getArgs();
        //判断非空和长度大于零，是则结束该通知
        if (args == null || args.length == 0) {
            return;
        }
        //取得方法参数数组的第一个元素
        Object object = args[0];
        LocalDateTime now = LocalDateTime.now();//获取当前时间
        Long CurrentId = BaseContext.getCurrentId();//获取当前操作人的id
        //3.通过反射获取四个set方法，（方法名，此参数类型的字节码）
        try {
            Method setCreateTime = object.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
            Method setCreateUser = object.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
            Method setUpdateTime = object.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method setUpdateUser = object.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
            //4.根据注解内的枚举判断是新增还是修改
            if (type == OperationType.INSERT) {
                //5.调用方法赋值，如果是新增，赋四个值
                setCreateTime.invoke(object, now);
                setCreateUser.invoke(object, CurrentId);
                setUpdateTime.invoke(object, now);
                setUpdateUser.invoke(object, CurrentId);
            } else if (type == OperationType.UPDATE) {
                //如果是修改，赋两个值，调用方法
                setUpdateTime.invoke(object, now);
                setUpdateUser.invoke(object, CurrentId);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //失败打日志，自动填充失败
            log.error(MessageConstant.AUTO_FILL_FAILED);
        }
    }
}
